package com.djicorp.rm.web.api.interceptor;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.djicorp.rm.web.api.common.SpringContextHolder;
import com.djicorp.rm.web.api.entity.DataAuditLog;
import com.djicorp.rm.web.api.mapper.DataAuditLogMapper;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Signature;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.concurrent.Executor;

@Component
@Slf4j
@Intercepts({
        @Signature(type = Executor.class, method = "delete", args={MappedStatement.class, Object.class})
})
public class DataAuditInnerInterceptor implements InnerInterceptor {

    private static DataAuditLogMapper dataAuditLogMapper;
    private static Gson gson;

    private static void checkComponent(){
        if(null == dataAuditLogMapper){
            Object obj = ((BaseMapper<?>) SpringContextHolder.getBean("dataAuditLogMapper"));
            dataAuditLogMapper = (DataAuditLogMapper) obj;
        }
        if(null == gson){
            gson = (Gson) SpringContextHolder.getBean("gson");
        }
    }

    @Override
    public void beforeUpdate(org.apache.ibatis.executor.Executor executor, MappedStatement ms, Object parameter) throws SQLException {
        if(ms.getSqlCommandType() == SqlCommandType.DELETE){
            try {
                // 反向操作：通过表名获取实体类（需提前注册表与实体的映射）
                Class<?> entityClass = getEntityClass(ms);
                Class clazz = Class.forName(ms.getId().substring(0, ms.getId().lastIndexOf(".")));
                TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
                if (tableInfo == null) {
                    return;
                };

                // 如果是审计表自身的增删改则直接返回，否则进入死循环
                if(tableInfo.getEntityType().equals(DataAuditLog.class)){
                    return;
                }

                Long recordId = Long.valueOf(parameter.toString());

                // 获取变更前数据
                Object oldData = ((BaseMapper<?>)SpringContextHolder.getBeanByClassSimpleName(clazz.getSimpleName()))
                        .selectById(recordId);

                // 异步保存日志
                saveAuditLogAsync(tableInfo, recordId, oldData, SqlCommandType.DELETE.toString());
            } catch (ClassNotFoundException e) {
                log.warn("记录审计日志找不到class,errMsg={}", e.getMessage());
            }
        }
    }

    // 异步保存日志
    @Async
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void saveAuditLogAsync(TableInfo tableInfo, Long recordId,
                                  Object oldData, String operationType) {
        try {
            checkComponent();
            DataAuditLog audit = DataAuditLog.builder()
                    .tableName(tableInfo.getTableName())
                    .recordId(recordId)
                    .operationType(operationType)
                    .oldData(oldData != null ? gson.toJson(oldData) : null)
                    .newData(null)
                    .operator("getCurrentUser()")
                    .build();

            dataAuditLogMapper.insert(audit);
        } catch (Exception e) {
            log.error("审计日志保存失败", e);
        }
    }

    public static Class<?> getEntityClass(MappedStatement mappedStatement) {
        try {
            // 方法一：通过泛型解析
            String mapperClassName = mappedStatement.getId().substring(0, mappedStatement.getId().lastIndexOf("."));
            Class<?> mapperClass = Class.forName(mapperClassName);
            Type genericType = mapperClass.getGenericInterfaces()[0];
            ParameterizedType parameterizedType = (ParameterizedType) genericType;
            return (Class<?>) parameterizedType.getActualTypeArguments()[0];
        } catch (Exception e) {
//            // 方法二：通过 TableInfo 反向查找
//            return TableInfoHelper.getTableInfos().stream()
//                    .filter(info -> info.getTableName().equals(getTableName(mappedStatement)))
//                    .findFirst()
//                    .map(TableInfo::getEntityType)
//                    .orElseThrow(() -> new RuntimeException("Entity class not found"));
        }

        return null;
    }


}
